<!DOCTYPE html>
<html lang=zh>
<head>
    <meta charset="utf-8">
    
    <title>6-mysql-索引作用和设计 | johnny技术地</title>
    
    
        <meta name="keywords" content="mysql" />
    
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
    <meta name="description" content="索引相关索引作用 即上述所说，索引能极大地减少扫描行数 索引可以帮助服务器避免排序和临时表 索引可以将随机 IO 变成顺序 IO  排序例子1SELECT * FROM user order by age desc;  则 MySQL 的流程是这样的，扫描所有行，把所有行加载到内存后，再按 age 排序生成一张临时表，再把这表排序后将相应行返回给客户端，更糟的，如果这张临时表的大小大于 tmp_t">
<meta property="og:type" content="article">
<meta property="og:title" content="6-mysql-索引作用和设计">
<meta property="og:url" content="https://abcd_1101.gitee.io/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/6-mysql-%E7%B4%A2%E5%BC%95%E4%BD%9C%E7%94%A8%E5%92%8C%E8%AE%BE%E8%AE%A1/index.html">
<meta property="og:site_name" content="johnny技术地">
<meta property="og:description" content="索引相关索引作用 即上述所说，索引能极大地减少扫描行数 索引可以帮助服务器避免排序和临时表 索引可以将随机 IO 变成顺序 IO  排序例子1SELECT * FROM user order by age desc;  则 MySQL 的流程是这样的，扫描所有行，把所有行加载到内存后，再按 age 排序生成一张临时表，再把这表排序后将相应行返回给客户端，更糟的，如果这张临时表的大小大于 tmp_t">
<meta property="og:locale">
<meta property="og:image" content="https://abcd_1101.gitee.io/gitee-internal-blog/images/mysql-b%E5%8A%A0%E6%A0%91.jpg">
<meta property="og:image" content="https://img2018.cnblogs.com/blog/725429/202002/725429-20200216140737968-740617209.png">
<meta property="og:image" content="https://pic1.zhimg.com/80/v2-4e1a4b77950dd47c7dfdb043c5661cbc_720w.png">
<meta property="article:published_time" content="2021-09-04T08:06:22.000Z">
<meta property="article:modified_time" content="2021-10-17T07:49:27.586Z">
<meta property="article:author" content="Johnny">
<meta property="article:tag" content="mysql">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://abcd_1101.gitee.io/gitee-internal-blog/images/mysql-b%E5%8A%A0%E6%A0%91.jpg">
    

    
        <link rel="alternate" href="/atom.xml" title="johnny技术地" type="application/atom+xml" />
    

    
        <link rel="icon" href="/gitee-internal-blog/favicon.ico" />
    

    
<link rel="stylesheet" href="/gitee-internal-blog/libs/font-awesome/css/font-awesome.min.css">

    
<link rel="stylesheet" href="/gitee-internal-blog/libs/open-sans/styles.css">

    
<link rel="stylesheet" href="/gitee-internal-blog/libs/source-code-pro/styles.css">


    
<link rel="stylesheet" href="/gitee-internal-blog/css/style.css">

    
<script src="/gitee-internal-blog/libs/jquery/2.1.3/jquery.min.js"></script>

    
<script src="/gitee-internal-blog/libs/jquery/plugins/cookie/1.4.1/jquery.cookie.js"></script>

    
    
        
<link rel="stylesheet" href="/gitee-internal-blog/libs/lightgallery/css/lightgallery.min.css">

    
    
        
<link rel="stylesheet" href="/gitee-internal-blog/libs/justified-gallery/justifiedGallery.min.css">

    
    
    
    


    
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    
<meta name="generator" content="Hexo 5.4.0"></head>

<body>
    <div id="container">
        <header id="header">
    <div id="header-main" class="header-inner">
        <div class="outer">
            <a href="/gitee-internal-blog/" id="logo">
                <i class="logo"></i>
                <span class="site-title">johnny技术地</span>
            </a>
            <nav id="main-nav">
                
                    <a class="main-nav-link" href="/gitee-internal-blog/">首页</a>
                
                    <a class="main-nav-link" href="/gitee-internal-blog/archives">归档</a>
                
                    <a class="main-nav-link" href="/gitee-internal-blog/categories">分类</a>
                
                    <a class="main-nav-link" href="/gitee-internal-blog/tags">标签</a>
                
                    <a class="main-nav-link" href="/gitee-internal-blog/about">关于</a>
                
            </nav>
            
            <div id="search-form-wrap">

    <form class="search-form">
        <input type="text" class="ins-search-input search-form-input" placeholder="Search" />
        <button type="submit" class="search-form-submit"></button>
    </form>
    <div class="ins-search">
    <div class="ins-search-mask"></div>
    <div class="ins-search-container">
        <div class="ins-input-wrapper">
            <input type="text" class="ins-search-input" placeholder="Type something..." />
            <span class="ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
        </div>
        <div class="ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>
<script>
(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: 'Posts',
            PAGES: 'Pages',
            CATEGORIES: 'Categories',
            TAGS: 'Tags',
            UNTITLED: '(Untitled)',
        },
        ROOT_URL: '/gitee-internal-blog/',
        CONTENT_URL: '/gitee-internal-blog/content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>

<script src="/gitee-internal-blog/js/insight.js"></script>


</div>
        </div>
    </div>
    <div id="main-nav-mobile" class="header-sub header-inner">
        <table class="menu outer">
            <tr>
                
                    <td><a class="main-nav-link" href="/gitee-internal-blog/">首页</a></td>
                
                    <td><a class="main-nav-link" href="/gitee-internal-blog/archives">归档</a></td>
                
                    <td><a class="main-nav-link" href="/gitee-internal-blog/categories">分类</a></td>
                
                    <td><a class="main-nav-link" href="/gitee-internal-blog/tags">标签</a></td>
                
                    <td><a class="main-nav-link" href="/gitee-internal-blog/about">关于</a></td>
                
                <td>
                    
    <div class="search-form">
        <input type="text" class="ins-search-input search-form-input" placeholder="Search" />
    </div>

                </td>
            </tr>
        </table>
    </div>
</header>

        <div class="outer">
            
            
                <aside id="sidebar">
   
        
    <div class="widget-wrap" id='categories'>
        <h3 class="widget-title">
            <span>categories</span>
            &nbsp;
            <a id='allExpand' href="#">
                <i class="fa fa-angle-double-down fa-2x"></i>
            </a>
        </h3>
        
        
        
         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            DLT
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            Ledger
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            Corda
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2023/03/09/DLT/Ledger/Corda/Corda%E4%BE%8B%E5%AD%90/">Corda例子</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            概念和框架
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2023/02/04/DLT/%E6%A6%82%E5%BF%B5%E5%92%8C%E6%A1%86%E6%9E%B6/%E5%8C%BA%E5%9D%97%E9%93%BE%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80/">区块链理论基础</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            IDE
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/05/03/IDE-eclipse-debug-f5-8/">IDE eclipse debug f5-8</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            docker_k8s
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/06/19/docker_k8s/springcloud%20vs%20k8s/"></a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/06/docker_k8s/%E5%AE%B9%E5%99%A8-docker-k8s/">容器-docker-k8s</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            git
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/04/05/git-reset-and-revert/">git reset and revert</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/04/14/git-pull-request-to-contribute-other-project/">Pull request to contribute other project</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/04/18/git-stash%E7%94%A8%E6%B3%95/">git stash用法</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/05/16/git-tag%E8%AE%B0%E5%BD%95%E7%89%88%E6%9C%AC%E5%AF%B9%E5%BA%94commit/">git tag记录版本对应commit</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            java
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/04/25/java%E5%9F%BA%E7%A1%801/">java基础1</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            jvm
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            性能监测
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/04/11/jvisualvm%E5%92%8Csprintboot%20admin%E6%80%A7%E8%83%BD%E7%9B%91%E6%B5%8B/">jvisualvm和sprintboot admin性能监测</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            linux
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            常用命令
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/04/11/linux%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/">linux常用命令</a></li>  </ul> 
                    </li> 
                     <li class="file"><a href="/gitee-internal-blog/2021/04/18/linux-find%E5%91%BD%E4%BB%A4/">linux-find命令</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            spring
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/05/01/spring-log%E6%97%A5%E5%BF%97%E8%AE%B0%E5%BD%95/">日志记录</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/05/03/spring-mvc%E5%BF%85%E5%A4%87%E9%85%8D%E7%BD%AE/">spring mvc必备配置</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/05/23/spring%E8%84%9A%E6%89%8B%E6%9E%B6%E5%8E%9F%E7%90%86/">spring脚手架原理</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            windows
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/04/17/windows-dns%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%9C%AA%E5%93%8D%E5%BA%94/">windows dns服务器未响应</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            中间件
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            mq
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/06/25/%E4%B8%AD%E9%97%B4%E4%BB%B6/mq/2-mq%E9%87%8D%E5%A4%8D%E9%A1%BA%E5%BA%8F%E6%B6%88%E8%B4%B9/">2-mq重复顺序消费</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E4%B8%AD%E9%97%B4%E4%BB%B6/mq/1-mq%E5%9F%BA%E7%A1%80/">1-mq基础</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E4%B8%AD%E9%97%B4%E4%BB%B6/mq/0-mq-zookeeper%E6%98%AF%E4%BB%80%E4%B9%88/">0-mq-zookeeper是什么</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E4%B8%AD%E9%97%B4%E4%BB%B6/mq/3-mq-kafka%E5%85%A5%E9%97%A8/">3-mq-kafka入门</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E4%B8%AD%E9%97%B4%E4%BB%B6/mq/4-mq%E9%97%AE%E9%A2%98%E4%B8%8D%E4%B8%A2%E5%A4%B1-%E9%87%8D%E5%A4%8D-%E6%9C%89%E5%BA%8F-%E5%A0%86%E7%A7%AF/">4-mq问题不丢失_重复_有序_堆积</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/05/%E4%B8%AD%E9%97%B4%E4%BB%B6/mq/5-mq-kafka-segement%E8%AF%BB%E5%86%99/">5-mq-kafka-segement读写</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/07/%E4%B8%AD%E9%97%B4%E4%BB%B6/mq/6-mq-kafka%E4%B8%89%E8%BF%9E%E5%87%BB/">6-mq-kafka三连击</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/12/%E4%B8%AD%E9%97%B4%E4%BB%B6/mq/7-mq-kafka%E6%98%AF%E6%8E%A8%E8%BF%98%E6%98%AF%E6%8B%89/">7-mq-kafka是推还是拉</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            必会框架
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/09/06/%E5%BF%85%E4%BC%9A%E6%A1%86%E6%9E%B6/%E6%A1%86%E6%9E%B6-%E9%AB%98%E6%80%A7%E8%83%BDNIO-Netty/">框架-高性能NIO-Netty</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            操作系统
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/09/06/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-pageCache/">操作系统-pageCache</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/06/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-nioFilechannel%E5%A0%86%E5%A4%96directBuffer%E4%B8%8E%E5%A0%86%E5%86%85byteBuffer/">操作系统-nioFilechannel堆外directBuffer与堆内byteBufferbyteBuffer</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/06/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E4%BC%98%E5%8C%96%E6%8F%A1%E6%89%8B%E6%8C%A5%E6%89%8B/">操作系统-计算机网络优化握手挥手</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/06/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%B8%B8%E9%97%AE/">操作系统-计算机网络常问</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/06/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%8A%93%E5%8C%85/">操作系统-计算机网络抓包</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory open">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder-open"></i>
                            &nbsp;
                            数据库
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory open">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder-open"></i>
                            &nbsp;
                            mysql
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/0-mysql%E7%BB%93%E6%9E%84%E4%B8%8E%E6%8F%92%E5%85%A5/">0-mysql结构与插入</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/1-mysql%E4%B8%80%E8%87%B4%E6%80%A7%E8%AF%BB-%E4%BA%8B%E5%8A%A1%E5%9B%9E%E6%BB%9A-mvcc/">1-mysql一致性读-事务回滚-mvcc</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/3-mysql-sql%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B%E5%AE%8F%E8%A7%82%E6%B5%81%E7%A8%8B-redo-undo-bin/">3-mysql-sql执行过程宏观流程-redo-undo-bin</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/5-mysql-sql%E8%B0%83%E4%BC%98%E6%80%9D%E8%B7%AF/">5-mysql-sql调优思路</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/4-mysql-explain%E6%89%A7%E8%A1%8C%E5%85%B7%E4%BD%93%E6%B5%81%E7%A8%8B/">4-mysql-explain执行具体流程</a></li>  <li class="file active"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/6-mysql-%E7%B4%A2%E5%BC%95%E4%BD%9C%E7%94%A8%E5%92%8C%E8%AE%BE%E8%AE%A1/">6-mysql-索引作用和设计</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/8-mysql-%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0%E8%AE%BE%E5%A4%9A%E5%A4%A7/">8-mysql-数据库连接池设多大</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/9-mysql-%E4%BB%8E%E4%B8%9A%E5%8A%A1%E5%88%B0%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AE%BE%E8%AE%A1-%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B/">9-mysql-从业务到数据库设计-软件工程</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/7-mysql-changebuffer-merge/">7-mysql-changebuffer-merge</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/2-mysql-undo-purge_bin_redo-flush%E8%84%8F%E9%A1%B5/">2-mysql-undo-purge_bin_redo-flush脏页</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/10-mysql-mysql8%E6%96%B0%E7%89%B9%E6%80%A7/">10-mysql-mysql8新特性</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/12-mysql-%E5%85%A8%E5%B1%80%E9%94%81-%E8%A1%A8%E9%94%81-%E8%A1%8C%E9%94%81/">12-mysql-全局锁-表锁-行锁</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/11-mysql-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E5%92%8C%E5%AE%9E%E6%88%98/">11-mysql-主从复制和实战</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/13-mysql-%E6%9E%B6%E6%9E%84%E6%96%B9%E6%A1%88/">13-mysql-架构方案</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            redis
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/8-redis-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E6%93%8D%E4%BD%9C/">8-redis-数据结构和操作</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/11-redis-%E5%8F%AF%E7%94%A8%E6%80%A7-mysql%E4%B8%80%E8%87%B4%E6%80%A7%E9%97%AE%E9%A2%98/">11-redis-可用性-mysql一致性问题</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/1-redis-%E5%A5%BD-%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF/">1-redis-好-使用场景</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/2-redis-%E5%BF%AB-%E5%86%85%E5%AD%98%E8%80%97%E5%B0%BD%E5%90%8E%E4%BC%9A%E6%80%8E%E6%A0%B7/">2-redis-快-内存耗尽后会怎样</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/3-redis-%E5%BF%AB-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E6%93%8D%E4%BD%9C/">3-redis-快-数据结构和操作</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/4-redis-%E5%BF%AB-%E4%B8%BA%E4%BD%95%E5%8F%98%E5%A4%9A%E7%BA%BF%E7%A8%8B/">4-redis-快-为何变多线程</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/7-redis-%E4%BC%98%E5%8C%96-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/"></a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/8-redis-%E4%BC%98%E5%8C%96-%E9%9B%AA%E5%B4%A9-%E7%A9%BF%E9%80%8F-%E5%87%BB%E7%A9%BF/">8-redis-优化-雪崩-穿透-击穿</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/9-redis-%E5%8F%AF%E7%94%A8%E6%80%A7-%E6%8C%81%E4%B9%85%E5%8C%96/">9-redis-可用性-持久化</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/20-redis-%E9%9D%A2%E8%AF%95%E9%A2%98/">20-redis-面试题</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/5-redis-%E5%BF%AB-%E5%A4%9A%E8%B7%AFio%E5%A4%8D%E7%94%A8/">5-redis-快-多路io复用</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/6-redis-%E4%BC%98%E5%8C%96-%E5%8F%98%E6%85%A2%E4%BA%86%E5%90%97/">6-redis-优化-变慢了吗</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/10-redis-%E5%8F%AF%E7%94%A8%E6%80%A7-%E9%9B%86%E7%BE%A4%E7%AF%87/">10-redis-可用性-集群篇</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            知识点框架
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            19-数据库
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/08/02/19-1-Oracle%E5%B8%B8%E8%80%83/">19-1-Oracle常考</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            2-jvm
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/06/25/2-1-JVM%E8%84%91%E5%9B%BE/">2-1-JVM脑图</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/25/2-2-JVM%E5%86%85%E5%AD%98%E5%8C%BA%E5%9F%9F/">2-2-JVM内存区域</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/26/2-3-jvm%E8%BF%90%E8%A1%8C%E6%97%B6%E5%86%85%E5%AD%98/">2-3-jvm运行时内存</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/26/2-4-%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6-%E7%AE%97%E6%B3%95-%E9%80%83%E9%80%B8%E5%88%86%E6%9E%90/">2-4-垃圾回收-算法-逃逸分析</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/27/2-5-java%E5%9B%9B%E7%A7%8D%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B/">2-5-java四种引用类型</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/28/2-6-7-gc%E7%AE%97%E6%B3%95%E5%92%8C%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E5%99%A8/">2-6-7-gc算法和垃圾收集器</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/28/2-8-java-io-and-nio/">2-8-java io and nio</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/29/2-9-jvm%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6/">2-9-jvm类加载机制</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            3-java集合
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/06/30/3-1-java%E6%8E%A5%E5%8F%A3%E7%BB%A7%E6%89%BF%E5%85%B3%E7%B3%BB%E4%B8%8E%E5%AE%9E%E7%8E%B0/">3-1-java接口继承关系与实现</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/30/3-2-List/">3-2-List</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/01/3-3-Set/">3-3-Set</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/01/3-4-Map%E6%98%A0%E5%B0%84/">3-4-Map映射</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            4-java多线程
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/07/02/4-1-2-%E5%A4%9A%E7%BA%BF%E7%A8%8B%E8%84%91%E5%9B%BE%E5%92%8C%E5%9B%9B%E7%A7%8D%E7%BA%BF%E7%A8%8B%E5%88%9B%E5%BB%BA%E6%96%B9%E6%B3%95/">4-1-2-多线程脑图和四种线程创建</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/02/4-3-4%E7%A7%8D%E7%BA%BF%E7%A8%8B%E6%B1%A0/">4-3-4种线程池</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/02/4-4-%E7%BA%BF%E7%A8%8B%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F5%E7%A7%8D%E7%8A%B6%E6%80%81/">4-4-线程生命周期5种状态</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/02/4-5-%E7%BB%88%E6%AD%A2%E7%BA%BF%E7%A8%8B4%E6%96%B9%E5%BC%8F/">4-5-终止线程4方式</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/02/4-6-7-sleep%E4%B8%8Ewait-start%E4%B8%8Erun/">4-6-7-sleep与wait-start与run</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/03/4-8-java%E5%90%8E%E5%8F%B0%E7%BA%BF%E7%A8%8B/">4-8-java后台线程</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/03/4-9-java%E9%94%81/">4-9-java锁</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/05/4-10-%E7%BA%BF%E7%A8%8B%E5%9F%BA%E6%9C%AC%E6%96%B9%E6%B3%95/">4-10-线程基本方法</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/06/4-11-%E7%BA%BF%E7%A8%8B%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2/">4-11-线程上下文切换</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/06/4-12-%E5%90%8C%E6%AD%A5%E9%94%81%E4%B8%8E%E6%AD%BB%E9%94%81/">4-12-同步锁与死锁</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/06/4-13-%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%8E%9F%E7%90%86/">4-13-线程池原理</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/08/4-14-%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97/">4-14-阻塞队列</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/10/4-15-cyclicBarrier-countdownlatch-semaphore/">4-15-cyclicBarrier-countdownlatch-semaphore</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/14/4-16-volatile%E5%85%B3%E9%94%AE%E5%AD%97%E4%BD%9C%E7%94%A8/">4-16-volatile关键字作用</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/14/4-17-%E4%B8%A4%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE/">4-17-两个线程共享数据</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/16/4-18-ThreadLocal%E4%BD%9C%E7%94%A8/">4-18-ThreadLocal作用</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/16/4-19-synchronized%E5%92%8Creentrantlock%E5%8C%BA%E5%88%AB/">4-19-synchronized和reentrantlock区别</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/17/4-20-ConcurrentHashMap/">4-20-ConcurrentHashMap</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/17/4-21-22-java%E7%BA%BF%E7%A8%8B%E8%B0%83%E5%BA%A6%E5%92%8C%E7%AE%97%E6%B3%95/">4-21-22-java线程调度和算法</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/17/4-23-cas%E6%AF%94%E8%BE%83%E5%B9%B6%E4%BA%A4%E6%8D%A2/">4-23-cas比较并交换</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/17/4-24-aqs%E6%8A%BD%E8%B1%A1%E7%9A%84%E9%98%9F%E5%88%97%E5%90%8C%E6%AD%A5%E5%99%A8/">4-24-aqs抽象的队列同步器</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            5-java基础
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/07/19/5-1-exception%E5%BC%82%E5%B8%B8%E5%88%86%E7%B1%BB%E5%8F%8A%E5%A4%84%E7%90%86/">5-1-exception异常分类及处理</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/20/5-2-java%E5%8F%8D%E5%B0%84/">5-2-java反射</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/22/5-3-java%E6%B3%A8%E8%A7%A3annotation/">5-3-java注解annotation</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/24/5-4-java%E5%86%85%E9%83%A8%E7%B1%BB/">5-4-java内部类</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/08/14/5-5-jdk8-lambda/">5-5-jdk8-lambda</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/08/14/5-6-RxJava/">5-6-RxJava</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/08/14/5-7-java-Observer%E6%8E%A5%E5%8F%A3%E5%92%8CObservable%E7%B1%BB/">5-7-java-Observer接口和Observable类</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            6-spring
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/05/03/6-2-springboot%E5%B8%B8%E8%80%83/">6-2-springboot常考</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/31/6-1-spring%E5%B8%B8%E8%80%83/">6-1-spring常考</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/08/28/6-3-springcloud%E7%94%A8%E8%BF%87%E7%9A%84/">6-3-springcloud用过的</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            面试的项目实现
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            中间件
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            es
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/06/25/%E4%B8%AD%E9%97%B4%E4%BB%B6/es/es/">es</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            微服务
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/08/21/%E9%9D%A2%E8%AF%95%E7%9A%84%E9%A1%B9%E7%9B%AE%E5%AE%9E%E7%8E%B0/%E5%BE%AE%E6%9C%8D%E5%8A%A1/hystrix/"></a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            数据库
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            mysql
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/09/04/%E9%9D%A2%E8%AF%95%E7%9A%84%E9%A1%B9%E7%9B%AE%E5%AE%9E%E7%8E%B0/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/0-mysql%E7%BB%93%E6%9E%84%E4%B8%8E%E6%8F%92%E5%85%A5/">0-mysql结构与插入</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            自动补全
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/06/25/%E9%9D%A2%E8%AF%95%E7%9A%84%E9%A1%B9%E7%9B%AE%E5%AE%9E%E7%8E%B0/%E8%87%AA%E5%8A%A8%E8%A1%A5%E5%85%A8/es%E8%87%AA%E5%8A%A8%E8%A1%A5%E5%85%A8/">es自动补全</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/08/21/%E9%9D%A2%E8%AF%95%E7%9A%84%E9%A1%B9%E7%9B%AE%E5%AE%9E%E7%8E%B0/%E8%87%AA%E5%8A%A8%E8%A1%A5%E5%85%A8/redis%E8%87%AA%E5%8A%A8%E8%A1%A5%E5%85%A8/"></a></li>  </ul> 
                    </li> 
                     <li class="file"><a href="/gitee-internal-blog/2021/06/25/%E9%9D%A2%E8%AF%95%E7%9A%84%E9%A1%B9%E7%9B%AE%E5%AE%9E%E7%8E%B0/IJP%E9%9D%A2%E8%AF%95%E9%A1%B9%E7%9B%AE%E5%AE%9E%E7%8E%B0/">IJP面试项目实现</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/25/%E9%9D%A2%E8%AF%95%E7%9A%84%E9%A1%B9%E7%9B%AE%E5%AE%9E%E7%8E%B0/Ex%E9%9D%A2%E8%AF%95%E9%A1%B9%E7%9B%AE%E5%AE%9E%E7%8E%B0/">Ex面试项目实现</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            面试题
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/06/25/%E9%9D%A2%E8%AF%95%E9%A2%98/SpringBoot+Tomcat+Nginx+Netty%E9%9D%A2%E8%AF%95%E9%A2%98/">SpringBoot+Tomcat+Nginx+Netty面试题</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/25/%E9%9D%A2%E8%AF%95%E9%A2%98/%E9%98%BF%E9%87%8C%E9%9D%A2%E8%AF%95%E4%BA%8C/">阿里面试题2</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/06/25/%E9%9D%A2%E8%AF%95%E9%A2%98/%E9%98%BF%E9%87%8C%E9%9D%A2%E8%AF%95%E4%B8%80/">阿里面试题1</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/08/16/%E9%9D%A2%E8%AF%95%E9%A2%98-java%E5%9F%BA%E7%A1%80%E9%9D%A2%E8%AF%9516%E9%97%AE/">面试题-java基础面试16问</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            项目经历
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            2019
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            xinge_notification
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/04/05/oracle_explain/">Oracle explain</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            2021
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            房贷项目
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/04/05/%E9%A1%B9%E7%9B%AE%E4%BB%8E0%E5%88%B01/">项目从0到1</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/04/12/email-telnet-smtp-health-check/">email telnet smtp health check</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/04/12/%E5%8E%8B%E6%B5%8B%E5%8F%82%E6%95%B0%E6%8C%87%E6%A0%87/">压测参数指标</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/04/12/checkmarx%E5%AE%89%E5%85%A8%E6%89%AB%E6%8F%8F/">checkmarx安全扫描</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/04/25/db-table-annotation/">db table annotation</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/04/25/jdbctemplate-sql-injection/">jdbctemplate sql injection</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            微信开发
                        </a>
                         <ul class="unstyled" id="tree" > 
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            安全
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/05/16/%E5%AE%89%E5%85%A8-java-ssl%E9%94%99%E8%AF%AF%E8%A7%A3%E5%86%B3%E7%A5%9E%E5%99%A8-net-debug%E5%8F%82%E6%95%B0/">安全-java ssl 错误解决神器 net debug参数</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/28/%E5%AE%89%E5%85%A8-%E5%8A%A0%E5%AF%86%E6%9C%BA/">安全-加密机</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            容器
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/07/28/%E6%9C%8D%E5%8A%A1%E5%99%A8/%E6%9C%8D%E5%8A%A1%E5%99%A8-IBM%20websphere%E7%BB%8F%E9%AA%8C%20-%20%E5%89%AF%E6%9C%AC/">服务器-IBM websphere经验</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/28/%E6%9C%8D%E5%8A%A1%E5%99%A8/%E6%9C%8D%E5%8A%A1%E5%99%A8-Tomcat%E7%BB%8F%E9%AA%8C/">服务器-Tomcat经验</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/07/28/%E6%9C%8D%E5%8A%A1%E5%99%A8/%E6%9C%8D%E5%8A%A1%E5%99%A8-IBM%20websphere%E7%BB%8F%E9%AA%8C/">服务器-IBM websphere经验</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/08/15/docker_k8s/%E5%AE%B9%E5%99%A8-k8s%E7%BD%91%E9%A1%B5%E5%B8%B8%E8%A7%81%E5%90%8D%E8%AF%8D/">容器-k8s网页常见名词</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/09/06/docker_k8s/%E5%AE%B9%E5%99%A8-Istio/">容器-Istio</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            小程序
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/05/16/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8FnavigateTo%E4%B8%8EredirectTo%E5%8C%BA%E5%88%AB/">小程序navigateTo与redirectTo区别</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/08/30/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E9%85%8D%E7%BD%AE/">微信小程序的配置</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            手机抓包
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/04/10/Fiddler%E5%AF%B9%E5%AE%89%E5%8D%93%E7%A7%BB%E5%8A%A8%E7%AB%AF%E7%9A%84%E6%8A%93%E5%8C%85%E6%B5%8B%E8%AF%95/">Fiddler对安卓移动端的抓包测试</a></li>  </ul> 
                    </li> 
                    
                    <li class="directory">
                        <a href="#" data-role="directory">
                            <i class="fa fa-folder"></i>
                            &nbsp;
                            高级群发系统
                        </a>
                         <ul class="unstyled" id="tree" >  <li class="file"><a href="/gitee-internal-blog/2021/05/09/Oracle-clob%E5%AD%97%E6%AE%B5/">Oracle clob字段</a></li>  </ul> 
                    </li> 
                     <li class="file"><a href="/gitee-internal-blog/2021/04/18/%E9%A1%B9%E7%9B%AE%E6%80%A7%E8%83%BD%E5%8F%82%E6%95%B0/">项目性能参数</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/05/09/%E5%BE%AE%E4%BF%A1%E6%8E%A5%E5%8F%A3%E6%B3%A8%E6%84%8F%E7%82%B9%E6%B1%87%E9%9B%86/">微信接口注意点汇集</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/05/09/%E5%BE%AE%E4%BF%A1%E4%B8%93%E7%BA%BF%E7%9A%84%E7%BD%91%E7%BB%9C%E5%B1%82%E7%90%86%E8%A7%A3/">专线的网络层理解</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/05/15/%E5%BE%AE%E4%BF%A1Sprint-plan/">Sprint plan</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/05/15/%E5%BE%AE%E4%BF%A1%E4%B8%8E%E9%93%B6%E8%81%94%E7%9A%84sso%E5%8D%95%E7%82%B9%E7%99%BB%E5%BD%95/">微信与银联的sso单点登录</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/05/22/G3%E8%87%AA%E5%8A%A8%E5%8C%96/">G3自动化</a></li>  <li class="file"><a href="/gitee-internal-blog/2021/05/29/%E5%BE%AE%E4%BF%A1%E9%A1%B9%E7%9B%AE%E5%BE%80ikp%E6%90%AC/">微信项目往ikp搬</a></li>  </ul> 
                    </li> 
                     </ul> 
                    </li> 
                     </ul> 
    </div>
    <script>
        $(document).ready(function() {
            var iconFolderOpenClass  = 'fa-folder-open';
            var iconFolderCloseClass = 'fa-folder';
            var iconAllExpandClass = 'fa-angle-double-down';
            var iconAllPackClass = 'fa-angle-double-up';
            // Handle directory-tree expansion:
            // 左键单独展开目录
            $(document).on('click', '#categories a[data-role="directory"]', function (event) {
                event.preventDefault();

                var icon = $(this).children('.fa');
                var expanded = icon.hasClass(iconFolderOpenClass);
                var subtree = $(this).siblings('ul');
                icon.removeClass(iconFolderOpenClass).removeClass(iconFolderCloseClass);
                if (expanded) {
                    if (typeof subtree != 'undefined') {
                        subtree.slideUp({ duration: 100 });
                    }
                    icon.addClass(iconFolderCloseClass);
                } else {
                    if (typeof subtree != 'undefined') {
                        subtree.slideDown({ duration: 100 });
                    }
                    icon.addClass(iconFolderOpenClass);
                }
            });
            // 右键展开下属所有目录
            $('#categories a[data-role="directory"]').bind("contextmenu", function(event){
                event.preventDefault();
                
                var icon = $(this).children('.fa');
                var expanded = icon.hasClass(iconFolderOpenClass);
                var listNode = $(this).siblings('ul');
                var subtrees = $.merge(listNode.find('li ul'), listNode);
                var icons = $.merge(listNode.find('.fa'), icon);
                icons.removeClass(iconFolderOpenClass).removeClass(iconFolderCloseClass);
                if(expanded) {
                    subtrees.slideUp({ duration: 100 });
                    icons.addClass(iconFolderCloseClass);
                } else {
                    subtrees.slideDown({ duration: 100 });
                    icons.addClass(iconFolderOpenClass);
                }
            })
            // 展开关闭所有目录按钮
            $(document).on('click', '#allExpand', function (event) {
                event.preventDefault();
                
                var icon = $(this).children('.fa');
                var expanded = icon.hasClass(iconAllExpandClass);
                icon.removeClass(iconAllExpandClass).removeClass(iconAllPackClass);
                if(expanded) {
                    $('#sidebar .fa.fa-folder').removeClass('fa-folder').addClass('fa-folder-open')
                    $('#categories li ul').slideDown({ duration: 100 });
                    icon.addClass(iconAllPackClass);
                } else {
                    $('#sidebar .fa.fa-folder-open').removeClass('fa-folder-open').addClass('fa-folder')
                    $('#categories li ul').slideUp({ duration: 100 });
                    icon.addClass(iconAllExpandClass);
                }
            });  
        });
    </script>

    
    <div id="toTop" class="fa fa-angle-up"></div>
</aside>
            
            <section id="main"><article id="post-数据库/mysql/6-mysql-索引作用和设计" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
                    <div class="article-meta">
                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/gitee-internal-blog/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/">数据库</a><i class="fa fa-angle-right"></i><a class="article-category-link" href="/gitee-internal-blog/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/">mysql</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link-link" href="/gitee-internal-blog/tags/mysql/" rel="tag">mysql</a>
    </div>

                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/6-mysql-%E7%B4%A2%E5%BC%95%E4%BD%9C%E7%94%A8%E5%92%8C%E8%AE%BE%E8%AE%A1/">
            <time datetime="2021-09-04T08:06:22.000Z" itemprop="datePublished">2021-09-04</time>
        </a>
    </div>


                        
                            <i class="fa fa-bar-chart"></i>
                            <span id="busuanzi_container_site_pv"><span id="busuanzi_value_page_pv"></span></span>    
                        
                        
                            <div class="article-meta-button">
                                <a target="_blank" rel="noopener" href='https://github.com/zthxxx/Wiki-site/raw/writing/source/_posts/数据库/mysql/6-mysql-索引作用和设计.md'> Source </a>
                            </div>
                            <div class="article-meta-button">
                                <a target="_blank" rel="noopener" href='https://github.com/zthxxx/Wiki-site/edit/writing/source/_posts/数据库/mysql/6-mysql-索引作用和设计.md'> Edit </a>
                            </div>
                            <div class="article-meta-button">
                                <a target="_blank" rel="noopener" href='https://github.com/zthxxx/Wiki-site/commits/writing/source/_posts/数据库/mysql/6-mysql-索引作用和设计.md'> History </a>
                            </div>
                        
                    </div>
                
                
    
        <h1 class="article-title" itemprop="name">
            6-mysql-索引作用和设计
        </h1>
    

            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
        
            
                <div id="toc" class="toc-article">
                <strong class="toc-title">Catalogue</strong>
                    <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E7%B4%A2%E5%BC%95%E7%9B%B8%E5%85%B3"><span class="toc-number">1.</span> <span class="toc-text">索引相关</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%B4%A2%E5%BC%95%E4%BD%9C%E7%94%A8"><span class="toc-number">1.1.</span> <span class="toc-text">索引作用</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%8E%92%E5%BA%8F%E4%BE%8B%E5%AD%90"><span class="toc-number">1.1.1.</span> <span class="toc-text">排序例子</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#b-%E6%A0%91%E7%9A%84%E9%9D%9E%E5%8F%B6%E5%AD%90%E4%B8%8D%E5%AD%98%E6%95%B0%E6%8D%AE%EF%BC%8C%E6%AF%94B%E6%A0%91%E8%8A%82%E7%82%B9%E5%AD%98%E5%A4%9A%E4%BA%86%E7%B4%A2%E5%BC%95%EF%BC%8C%E6%AF%94%E5%93%88%E5%B8%8C%E7%B4%A2%E5%BC%95%E5%A4%9A%E4%BA%86%E6%8E%92%E5%BA%8F%EF%BC%8C%E5%88%A9%E7%94%A8%E9%A1%BA%E5%BA%8Fio%E9%A2%84%E8%AF%BB%E6%9B%B4%E5%BF%AB%E5%91%BD%E4%B8%AD"><span class="toc-number">1.1.2.</span> <span class="toc-text">b+树的非叶子不存数据，比B树节点存多了索引，比哈希索引多了排序，利用顺序io预读更快命中</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Io%E7%BB%86%E8%8A%82"><span class="toc-number">1.1.2.1.</span> <span class="toc-text">Io细节</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#iops"><span class="toc-number">1.1.2.1.1.</span> <span class="toc-text">iops</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%A2%84%E8%AF%BB"><span class="toc-number">1.1.2.1.2.</span> <span class="toc-text">预读</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%85%B7%E4%BD%93%E6%B5%81%E7%A8%8B"><span class="toc-number">1.1.2.1.3.</span> <span class="toc-text">具体流程</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%85%B7%E4%BD%93%E6%95%B0%E6%8D%AE"><span class="toc-number">1.1.2.1.4.</span> <span class="toc-text">具体数据</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BC%8A%E7%AB%AF"><span class="toc-number">1.2.</span> <span class="toc-text">弊端</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%B4%A2%E5%BC%95%E7%B1%BB%E5%88%AB"><span class="toc-number">1.3.</span> <span class="toc-text">索引类别</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#b-%E6%A0%91%E7%B4%A2%E5%BC%95"><span class="toc-number">1.3.1.</span> <span class="toc-text">b+树索引</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%93%88%E5%B8%8C%E7%B4%A2%E5%BC%95"><span class="toc-number">1.3.2.</span> <span class="toc-text">哈希索引</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%A4%E8%80%85%E5%8C%BA%E5%88%AB"><span class="toc-number">1.3.3.</span> <span class="toc-text">两者区别</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%AB%98%E6%80%A7%E8%83%BD%E7%B4%A2%E5%BC%95%E7%AD%96%E7%95%A5"><span class="toc-number">1.4.</span> <span class="toc-text">高性能索引策略</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8A%A0%E4%BA%86%E7%B4%A2%E5%BC%95%EF%BC%8C%E4%B8%BA%E4%BD%95%E5%8D%B4%E4%B8%8D%E7%94%9F%E6%95%88"><span class="toc-number">1.4.1.</span> <span class="toc-text">加了索引，为何却不生效</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%97%A0%E6%B3%95%E9%81%BF%E5%85%8D%E5%AF%B9%E7%B4%A2%E5%BC%95%E5%88%97%E4%BD%BF%E7%94%A8%E5%87%BD%E6%95%B0%EF%BC%8C%E6%80%8E%E4%B9%88%E4%BD%BF%E7%94%A8%E7%B4%A2%E5%BC%95"><span class="toc-number">1.4.2.</span> <span class="toc-text">无法避免对索引列使用函数，怎么使用索引</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%89%8D%E7%BC%80%E7%B4%A2%E5%BC%95%E4%B8%8E%E7%B4%A2%E5%BC%95%E9%80%89%E6%8B%A9%E6%80%A7cardinality"><span class="toc-number">1.4.3.</span> <span class="toc-text">前缀索引与索引选择性cardinality</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%B4%A2%E5%BC%95%E8%AE%BE%E8%AE%A1%E5%87%86%E5%88%99%EF%BC%9A%E4%B8%89%E6%98%9F%E7%B4%A2%E5%BC%95"><span class="toc-number">1.5.</span> <span class="toc-text">索引设计准则：三星索引</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#N%E5%8F%89%E6%A0%91%EF%BC%8C%E8%B7%B3%E8%A1%A8skiplist%EF%BC%8Clsm%EF%BC%88Log-Structured-MergeTree%EF%BC%89"><span class="toc-number">1.6.</span> <span class="toc-text">N叉树，跳表skiplist，lsm（Log-Structured MergeTree）</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#b%E6%A0%91"><span class="toc-number">1.6.1.</span> <span class="toc-text">b树</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#mongodb-%E7%94%A8b%E6%A0%91%E7%B4%A2%E5%BC%95"><span class="toc-number">1.6.1.1.</span> <span class="toc-text">mongodb 用b树索引</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Mongo-db%E5%B0%91%E7%94%A8%E5%85%B3%E8%81%94"><span class="toc-number">1.6.1.2.</span> <span class="toc-text">Mongo db少用关联</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8C%BA%E5%88%AB%E6%80%BB%E7%BB%93"><span class="toc-number">1.6.1.3.</span> <span class="toc-text">区别总结</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#b-%E5%A5%BD%E5%A4%84"><span class="toc-number">1.6.1.4.</span> <span class="toc-text">b+好处</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BA%A2%E9%BB%91%E6%A0%91"><span class="toc-number">1.6.2.</span> <span class="toc-text">红黑树</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%80%A7%E8%B4%A8"><span class="toc-number">1.6.2.1.</span> <span class="toc-text">性质</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%80%82%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-number">1.6.2.2.</span> <span class="toc-text">适用场景</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BA%A2%E9%BB%91%EF%BC%8Cb-%E6%A0%91%E7%9A%84%E7%94%A8%E9%80%94%E5%8C%BA%E5%88%AB"><span class="toc-number">1.6.2.3.</span> <span class="toc-text">红黑，b+树的用途区别</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#LSM-%E6%A0%91"><span class="toc-number">1.6.3.</span> <span class="toc-text">LSM 树</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%B7%B3%E8%A1%A8%EF%BC%88%E6%AF%94%E7%BA%A2%E9%BB%91%E6%A0%91%E6%9B%B4%E5%A5%BD%E6%93%8D%E4%BD%9C%EF%BC%89"><span class="toc-number">1.6.4.</span> <span class="toc-text">跳表（比红黑树更好操作）</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%B8%BA%E4%BD%95redis-%E4%BD%BF%E7%94%A8%E8%B7%B3%E8%A1%A8%E5%81%9A%E7%B4%A2%E5%BC%95%EF%BC%8C%E5%8D%B4%E4%B8%8D%E6%98%AF%E7%94%A8B-%E6%A0%91%E5%81%9A%E7%B4%A2%E5%BC%95%E3%80%82"><span class="toc-number">1.6.4.1.</span> <span class="toc-text">为何redis 使用跳表做索引，却不是用B+树做索引。</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%B8%BA%E4%BD%95%E4%B8%8D%E7%94%A8%E7%BA%A2%E9%BB%91%E6%A0%91%E7%94%A8%E8%B7%B3%E8%A1%A8"><span class="toc-number">1.6.4.2.</span> <span class="toc-text">为何不用红黑树用跳表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AE%9E%E4%BE%8B"><span class="toc-number">1.6.4.3.</span> <span class="toc-text">实例</span></a></li></ol></li></ol></li></ol></li></ol>
                </div>
            
        
        
            <h1 id="索引相关"><a href="#索引相关" class="headerlink" title="索引相关"></a>索引相关</h1><h2 id="索引作用"><a href="#索引作用" class="headerlink" title="索引作用"></a>索引作用</h2><ol>
<li>即上述所说，索引能极大地减少扫描行数</li>
<li>索引可以帮助服务器避免排序和临时表</li>
<li>索引可以将随机 IO 变成顺序 IO</li>
</ol>
<h3 id="排序例子"><a href="#排序例子" class="headerlink" title="排序例子"></a>排序例子</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM user order by age desc;</span><br></pre></td></tr></table></figure>

<p>则 MySQL 的流程是这样的，扫描所有行，把所有行加载到内存后，再按 age 排序生成一张临时表，再把这表排序后将相应行返回给客户端，更糟的，如果这张临时表的大小大于 tmp_table_size 的值（默认为 16 M），内存临时表会转为磁盘临时表，性能会更差，如果加了索引，索引本身是有序的 ，所以从磁盘读的行数本身就是按 age 排序好的，也就不会生成临时表，就不用再额外排序 ，无疑提升了性能。</p>
<h3 id="b-树的非叶子不存数据，比B树节点存多了索引，比哈希索引多了排序，利用顺序io预读更快命中"><a href="#b-树的非叶子不存数据，比B树节点存多了索引，比哈希索引多了排序，利用顺序io预读更快命中" class="headerlink" title="b+树的非叶子不存数据，比B树节点存多了索引，比哈希索引多了排序，利用顺序io预读更快命中"></a>b+树的非叶子不存数据，比B树节点存多了索引，比哈希索引多了排序，利用顺序io预读更快命中</h3><p>磁道上的菜就类比扇区（sector）中的信息，磁盘块（block）是由多个相邻的扇区组成的，是操作系统读取的最小单元，这样如果信息能以 block 的形式聚集在一起，就能极大减少磁盘 IO 时间,这就是顺序 IO 带来的性能提升，下文中我们将会看到 B+ 树索引。<em>多个扇区组成了一个 block，如果要读的信息都在这个 block 中，则只需一次 IO 读</em>而如果信息在一个磁道中分散地分布在各个扇区中，或者分布在不同磁道的扇区上（寻道时间是随机IO主要瓶颈所在），将会造成随机 IO，影响性能。</p>
<h4 id="Io细节"><a href="#Io细节" class="headerlink" title="Io细节"></a>Io细节</h4><p>磁盘IO，磁盘读取数据靠的是机械运动，每一次读取数据需要<strong>寻道、寻点、拷贝到内存</strong>三步操作。</p>
<p><strong>寻道</strong>时间是磁臂移动到指定磁道所需要的时间，一般在5ms以下；</p>
<p><strong>寻点</strong>是从磁道中找到数据存在的那个点，平均时间是半圈时间，如果是一个7200转/min的磁盘，寻点时间平均是60s*1000ms/(7200*2)=4ms</p>
<p><strong>拷贝到内存</strong>的时间很快，和前面两个时间比起来可以忽略不计，所以一<strong>次IO的时间平均是在9ms左右</strong>。听起来很快，但数据库百万级别的数据过一遍就达到了9000s，显然就是灾难级别的了。</p>
<h5 id="iops"><a href="#iops" class="headerlink" title="iops"></a>iops</h5><p>磁盘的最大IOPS，即IOPS = 1000 ms/ (Tseek寻道 + Troatation转动寻点)，忽略数据传输时间。假设磁盘平均物理寻道时间为3ms, 磁盘<strong>转速</strong>为7200,10K,15K rpm，则磁盘IOPS理论最大值分别为，</p>
<p>IOPS = 1000 / (3 + 60000/7200/2) = 140</p>
<p>IOPS = 1000 / (3 + 60000/10000/2) = 167</p>
<p>IOPS = 1000 / (3 + 60000/15000/2) = 200</p>
<p><a target="_blank" rel="noopener" href="https://cloud.tencent.com/document/product/236/47905">https://cloud.tencent.com/document/product/236/47905</a></p>
<p>腾讯云高达24万iops，这个就是理论上的qps。</p>
<h5 id="预读"><a href="#预读" class="headerlink" title="预读"></a>预读</h5><p>当一次IO时，不光把当前磁盘地址的数据，而是把<strong>相邻的数据</strong>也都读取到内存缓冲区内，因为当计算机访问一个地址的数据的时候，与其相邻的数据也会很快被访问到。</p>
<p>每一次IO读取的数据我们称之为一页(page)，具体一页有多大数据跟操作系统有关，一般为4k或8k，也就是我们读取一页内的数据时候，实际上才发生了一次IO。</p>
<p>优化数据库查询，就要<strong>尽量减少磁盘的IO操作</strong>，所以就出现了索引。</p>
<h5 id="具体流程"><a href="#具体流程" class="headerlink" title="具体流程"></a>具体流程</h5><p><img src="/gitee-internal-blog/images/mysql-b%E5%8A%A0%E6%A0%91.jpg" alt="image-20210925163806946"></p>
<p>来模拟下查找key为29的data的过程：</p>
<p>1、根据根结点指针读取文件目录的根磁盘块1。【磁盘IO操作<strong>1次</strong>】</p>
<p>2、磁盘块1存储17，35和三个指针数据。我们发现17&lt;29&lt;35，因此我们找到指针p2。</p>
<p>3、根据p2指针，我们定位并读取磁盘块3。【磁盘IO操作<strong>2次</strong>】</p>
<p>4、磁盘块3存储26，30和三个指针数据。我们发现26&lt;29&lt;30，因此我们找到指针p2。</p>
<p>5、根据p2指针，我们定位并读取磁盘块8。【磁盘IO操作<strong>3次</strong>】</p>
<p>6、磁盘块8中存储28，29。我们找到29，获取29所对应的数据data。</p>
<blockquote>
<p>由此可见，BTree索引使每次磁盘I/O取到内存的数据都发挥了作用，从而提高了查询效率。</p>
</blockquote>
<h5 id="具体数据"><a href="#具体数据" class="headerlink" title="具体数据"></a>具体数据</h5><p>InnoDB存储引擎中页的大小为16KB，一般表的主键类型为INT（占用4个字节）或BIGINT（占用8个字节），指针类型也一般为4或8个字节，也就是说一个页（B+Tree中的一个节点）中大概存储16KB/(8B+8B)=1K个键值（因为是估值，为方便计算，这里的K取值为〖10〗^3）。</p>
<p>假设每行数据1kB，那叶子节点就是16个数据。</p>
<p>1k*1k*16=2千万数据，大概三层。我们只需要进行三次的IO操作就可以从10亿条数据中找到我们想要的数据，比起最开始的百万数据9000秒不知道好多少。</p>
<h2 id="弊端"><a href="#弊端" class="headerlink" title="弊端"></a>弊端</h2><p>造成以下<strong>弊端</strong>：</p>
<ul>
<li>创建索引和维护索引要耗费时间，这种时间随着数据量的增加而增加。</li>
<li>除了数据表占数据空间之外，每一个索引还要占一定的物理空间。如果要建立聚簇索引，那么需要的空间就会更大。</li>
<li>当对表中的数据进行增加、删除和修改的时候，索引也要动态地维护，这样就降低了数据的维护速度。</li>
</ul>
<h2 id="索引类别"><a href="#索引类别" class="headerlink" title="索引类别"></a>索引类别</h2><h3 id="b-树索引"><a href="#b-树索引" class="headerlink" title="b+树索引"></a>b+树索引</h3><p>B+ 树是以 N 叉树的形式存在的，这样有效降低了树的高度，查找数据也不需要全表扫描了，顺着根节点层层往下查找能很快地找到我们的目标数据，<strong>每个节点的大小即一个磁盘块的大小，一次 IO 会将一个页（每页包含多个磁盘块）的数据都读入（即磁盘预读，程序局部性原理:读到了某个值，很大可能这个值周围的数据也会被用到，干脆一起读入内存）</strong>，</p>
<p><strong>叶子节点通过指针的相互指向连接，能有效减少顺序遍历时的随机 IO</strong>，而且我们也可以看到，叶子节点都是按索引的顺序排序好的，这也意味着根据索引查找或排序都是排序好了的，不会再在内存中形成临时表。</p>
<p>一个重要特性，利用了操作系统空间局部性原理，每次将树的相邻（有序）叶子节点加载到内存中。</p>
<ul>
<li>B树：非叶子节点和叶子节点都会存储数据。</li>
<li>B+树：只有叶子节点才会存储数据，非叶子节点至存储键值。叶子节点之间使用双向指针连接，最底层的叶子节点形成了一个双向有序链表。</li>
</ul>
<h3 id="哈希索引"><a href="#哈希索引" class="headerlink" title="哈希索引"></a>哈希索引</h3><p>哈希表的劣势也是比较明显的，<strong>不支持区间查找，不支持排序。</strong></p>
<p>假设我们在 db 某张表中有个 url 字段，我们知道每个 url 的长度都很长，如果以 url 这个字段创建索引，无疑要占用很大的存储空间，如果能通过哈希（比如CRC32）把此 url 映射成 4 个字节，再以此哈希值作索引 ，索引占用无疑大大缩短。</p>
<blockquote>
<p>那Hash表在哪些场景比较适合？</p>
</blockquote>
<p>等值查询的场景，就只有KV（Key，Value）的情况，例如Redis、Memcached等这些NoSQL的中间件。</p>
<blockquote>
<p>你说的是无序的Hash表，那有没有有序的数据结构？</p>
</blockquote>
<p><strong>有序数组</strong>，它就比较优秀了呀，它在等值查询的和范围查询的时候都很Nice。</p>
<blockquote>
<p>那它完全没有缺点么？</p>
</blockquote>
<p>不是的，有序的适合静态数据，因为如果我们新增、删除、修改数据的时候就会改变他的结构。</p>
<p>比如你新增一个，那在你新增的位置后面所有的节点都会后移，成本很高。</p>
<blockquote>
<p>那照你这么说他根本就不优秀啊，特点也没地方放。</p>
</blockquote>
<p>此言差矣，可以用来做静态存储引擎啊，用来保存静态数据，例如你2019年的支付宝账单，2019年的淘宝购物记录等等都是很合适的，都是不会变动的历史数据。</p>
<blockquote>
<p>有点东西啊小伙子，那二叉树呢？</p>
</blockquote>
<p>二叉树是有序的，所以是支持范围查询的。</p>
<p>但是他的时间复杂度是O(log(N))，为了维持这个时间复杂度，更新的时间复杂度也得是O(log(N))，那就得保持这棵树是完全平衡二叉树了。</p>
<blockquote>
<p>怎么听你一说，平衡二叉树用来做索引还不错呢？</p>
</blockquote>
<p>此言差矣，索引也不只是在内存里面存储的，还是要落盘持久化的，可以看到图中才这么一点数据，如果数据多了，树高会很高，查询的成本就会随着树高的增加而增加。</p>
<p>为了节约成本很多公司的磁盘还是采用的机械硬盘，这样一次千万级别的查询差不多就要10秒了，这谁顶得住啊？</p>
<blockquote>
<p>如果用B树呢？</p>
</blockquote>
<p>同理来看看B树的结构：</p>
<p>可以发现同样的元素，B树的表示要比完全平衡二叉树要“矮”，原因在于B树中的一个节点可以存储多个元素。</p>
<p>B树其实就已经是一个不错的数据结构，用来做索引效果还是不错的。</p>
<blockquote>
<p>那为啥没用B树，而用了B+树？</p>
</blockquote>
<p>一样先看一下B加的结构：</p>
<p>B+树的表示要比B树要“胖”，原因在于B+树中的非叶子节点会冗余一份在叶子节点中，并且叶子节点之间用指针相连。</p>
<blockquote>
<p>那么B+树到底有什么优势呢？</p>
</blockquote>
<p>其实很简单，我们看一下上面的数据结构，最开始的Hash不支持范围查询，二叉树树高很高，只有B树跟B+有的一比。</p>
<p>B树一个节点可以存储多个元素，相对于完全平衡二叉树整体的树高降低了，磁盘IO效率提高了。</p>
<p>而B+树是B树的升级版，只是把非叶子节点冗余一下，这么做的好处是<strong>为了提高范围查找的效率</strong>。</p>
<p>提高了的原因也无非是会有指针指向下一个节点的叶子节点。</p>
<blockquote>
<p>B+树中一个节点到底多大合适？</p>
</blockquote>
<p><strong>B+树中一个节点为一页或页的倍数最为合适</strong>。</p>
<blockquote>
<p>为啥？</p>
</blockquote>
<p>因为如果一个节点的大小小于1页，那么读取这个节点的时候其实也会读出1页，造成资源的浪费。</p>
<p>如果一个节点的大小大于1页，比如1.2页，那么读取这个节点的时候会读出2页，也会造成资源的浪费。</p>
<p>所以为了不造成浪费，所以最后把一个节点的大小控制在1页、2页、3页、4页等倍数页大小最为合适。</p>
<h3 id="两者区别"><a href="#两者区别" class="headerlink" title="两者区别"></a>两者区别</h3><blockquote>
<p>Hash 索引和 B+ 树索引区别是什么？你在设计索引是怎么抉择的？</p>
</blockquote>
<ul>
<li>B+ 树可以进行范围查询，Hash 索引不能。</li>
<li>B+ 树支持联合索引的最左侧原则，Hash 索引不支持。</li>
<li>B+ 树支持 order by 排序，Hash 索引不支持。</li>
<li>Hash 索引在等值查询上比 B+ 树效率更高。</li>
<li>B+ 树使用 like 进行模糊查询的时候，like 后面（比如%开头）的话可以起到优化的作用，Hash 索引根本无法进行模糊查询。</li>
</ul>
<h2 id="高性能索引策略"><a href="#高性能索引策略" class="headerlink" title="高性能索引策略"></a>高性能索引策略</h2><h3 id="加了索引，为何却不生效"><a href="#加了索引，为何却不生效" class="headerlink" title="加了索引，为何却不生效"></a>加了索引，为何却不生效</h3><p>加了索引却不生效可能会有以下几种原因</p>
<p>1、索引列是表示式的一部分，或是函数的一部分</p>
<p>如下 SQL：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT book_id FROM BOOK WHERE book_id + 1 &#x3D; 5;</span><br></pre></td></tr></table></figure>

<p>或者</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT book_id FROM BOOK WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(gmt_create) &lt;&#x3D; 10</span><br></pre></td></tr></table></figure>

<p>上述两个 SQL 虽然在列 book_id 和 gmt_create 设置了索引 ，但由于它们是表达式或函数的一部分，导致索引无法生效，最终导致全表扫描。</p>
<p>2、隐式类型转换</p>
<p>以上两种情况相信不少人都知道索引不能生效，但下面这种隐式类型转换估计会让不少人栽跟头，来看下下面这个例子:</p>
<p>假设有以下表:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE &#96;tradelog&#96; (</span><br><span class="line">  &#96;id&#96; int(11) NOT NULL,</span><br><span class="line">  &#96;tradeid&#96; varchar(32) DEFAULT NULL,</span><br><span class="line">  &#96;operator&#96; int(11) DEFAULT NULL,</span><br><span class="line">  &#96;t_modified&#96; datetime DEFAULT NULL,</span><br><span class="line">   PRIMARY KEY (&#96;id&#96;),</span><br><span class="line">   KEY &#96;tradeid&#96; (&#96;tradeid&#96;),</span><br><span class="line">   KEY &#96;t_modified&#96; (&#96;t_modified&#96;)</span><br><span class="line">) ENGINE&#x3D;InnoDB DEFAULT CHARSET&#x3D;utf8mb4;</span><br></pre></td></tr></table></figure>

<p>执行 SQL 语句</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM tradelog WHERE tradeid&#x3D;110717;</span><br></pre></td></tr></table></figure>

<p>交易编号 tradeid 上有索引，但用 EXPLAIN 执行却发现使用了全表扫描，为啥呢，tradeId 的类型是 varchar(32), 而此 SQL 用 tradeid 一个数字类型进行比较，发生了隐形转换，会隐式地将字符串转成整型，如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; SELECT * FROM tradelog WHERE CAST(tradid AS signed int) &#x3D; 110717;</span><br></pre></td></tr></table></figure>

<p>这样也就触发了上文中第一条的规则 ，即：索引列不能是函数的一部分。</p>
<p>3、隐式编码转换</p>
<p>这种情况非常隐蔽，来看下这个例子</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE &#96;trade_detail&#96; ( </span><br><span class="line"> &#96;id&#96; int(11) NOT NULL, </span><br><span class="line"> &#96;tradeid&#96; varchar(32) DEFAULT NULL, </span><br><span class="line"> &#96;trade_step&#96; int(11) DEFAULT NULL, &#x2F;*操作步骤*&#x2F; </span><br><span class="line"> &#96;step_info&#96; varchar(32) DEFAULT NULL, &#x2F;*步骤信息*&#x2F; </span><br><span class="line">   PRIMARY KEY (&#96;id&#96;), KEY &#96;tradeid&#96; (&#96;tradeid&#96;)</span><br><span class="line">) ENGINE&#x3D;InnoDB DEFAULT CHARSET&#x3D;utf8;</span><br></pre></td></tr></table></figure>

<p>trade_defail 是交易详情， tradelog 是操作此交易详情的记录，现在要查询 id=2 的交易的所有操作步骤信息，则我们会采用如下方式</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT d.* FROM tradelog l, trade_detail d WHERE d.tradeid&#x3D;l.tradeid AND l.id&#x3D;2;</span><br></pre></td></tr></table></figure>

<p>由于 tradelog 与 trade_detail 这两个表的字符集不同，且 tradelog 的字符集是 utf8mb4，而 trade_detail 字符集是 utf8, utf8mb4 是 utf8 的超集，所以会自动将 utf8 转成 utf8mb4。即上述语句会发生如下转换:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT d.* FROM tradelog l, trade_detail d WHERE (CONVERT(d.traideid USING utf8mb4)))&#x3D;l.tradeid AND l.id&#x3D;2;</span><br></pre></td></tr></table></figure>

<p>自然也就触发了 「索引列不能是函数的一部分」这条规则。怎么解决呢，第一种方案当然是把两个表的字符集改成一样，如果业务量比较大，生产上不方便改的话，还有一种方案是把 utf8mb4 转成 utf8，如下</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; SELECT d.* FROM tradelog l , trade_detail d WHERE d.tradeid&#x3D;CONVERT(l.tradeid USING utf8) AND l.id&#x3D;2; </span><br></pre></td></tr></table></figure>

<p>这样索引列就生效了。</p>
<p>4、使用 order by 造成的全表扫描</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM user ORDER BY age DESC</span><br></pre></td></tr></table></figure>

<p>上述语句在 age 上加了索引，但依然造成了全表扫描，这是因为我们使用了 SELECT *,导致回表查询，MySQL 认为回表的代价比全表扫描更大，所以不选择使用索引，如果想使用到 age 的索引，我们可以用覆盖索引来代替:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT age FROM user ORDER BY age DESC</span><br></pre></td></tr></table></figure>

<p>或者加上 limit 的条件（数据比较小）</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM user ORDER BY age DESC limit 10</span><br></pre></td></tr></table></figure>

<p>这样就能利用到索引。</p>
<h3 id="无法避免对索引列使用函数，怎么使用索引"><a href="#无法避免对索引列使用函数，怎么使用索引" class="headerlink" title="无法避免对索引列使用函数，怎么使用索引"></a>无法避免对索引列使用函数，怎么使用索引</h3><p>有时候我们无法避免对索引列使用函数，但这样做会导致全表索引，是否有更好的方式呢。</p>
<p>比如我现在就是想记录 2016 ~ 2018 所有年份 7月份的交易记录总数</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; SELECT count(*) FROM tradelog WHERE month(t_modified)&#x3D;7;</span><br></pre></td></tr></table></figure>

<p>由于索引列是函数的参数，所以显然无法用到索引，我们可以将它改造成基本字段区间的查找如下</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">SELECT count(*) FROM tradelog WHERE</span><br><span class="line">    -&gt; (t_modified &gt;&#x3D; &#39;2016-7-1&#39; AND t_modified&lt;&#39;2016-8-1&#39;) or</span><br><span class="line">    -&gt; (t_modified &gt;&#x3D; &#39;2017-7-1&#39; AND t_modified&lt;&#39;2017-8-1&#39;) or </span><br><span class="line">    -&gt; (t_modified &gt;&#x3D; &#39;2018-7-1&#39; AND t_modified&lt;&#39;2018-8-1&#39;);</span><br></pre></td></tr></table></figure>

<h3 id="前缀索引与索引选择性cardinality"><a href="#前缀索引与索引选择性cardinality" class="headerlink" title="前缀索引与索引选择性cardinality"></a>前缀索引与索引选择性cardinality</h3><p>之前我们说过，如于长字符串的字段（如 url），我们可以用伪哈希索引的形式来创建索引，以避免索引变得既大又慢，除此之外其实还可以用前缀索引（字符串的部分字符）的形式来达到我们的目的，那么这个前缀索引应该如何选取呢，这叫涉及到一个叫索引选择性的概念</p>
<blockquote>
<p>索引选择性：不重复的索引值（也称为基数，cardinality）和数据表的记录总数的比值，比值越高，代表索引的选择性越好，唯一索引的选择性是最好的，比值是 1。</p>
</blockquote>
<p>画外音：我们可以通过 <strong>SHOW INDEXES FROM table</strong> 来查看每个索引 cardinality 的值以评估索引设计的合理性</p>
<p>怎么选择这个比例呢，我们可以分别取前 3，4，5，6，7 的前缀索引，然后再比较下选择这几个前缀索引的选择性，执行以下语句</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">SELECT </span><br><span class="line"> COUNT(DISTINCT LEFT(city,3))&#x2F;COUNT(*) as sel3,</span><br><span class="line"> COUNT(DISTINCT LEFT(city,4))&#x2F;COUNT(*) as sel4,</span><br><span class="line"> COUNT(DISTINCT LEFT(city,5))&#x2F;COUNT(*) as sel5,</span><br><span class="line"> COUNT(DISTINCT LEFT(city,6))&#x2F;COUNT(*) as sel6,</span><br><span class="line"> COUNT(DISTINCT LEFT(city,7))&#x2F;COUNT(*) as sel7</span><br><span class="line">FROM city_demo</span><br></pre></td></tr></table></figure>

<p>得结果如下</p>
<table>
<thead>
<tr>
<th align="left">sel3</th>
<th align="left">sel4</th>
<th align="left">sel5</th>
<th align="left">sel6</th>
<th align="left">sel7</th>
</tr>
</thead>
<tbody><tr>
<td align="left">0.0239</td>
<td align="left">0.0293</td>
<td align="left">0.0305</td>
<td align="left">0.0309</td>
<td align="left">0.0310</td>
</tr>
</tbody></table>
<p>可以看到当前缀长度为 7 时，索引选择性提升的比例已经很小了，也就是说应该选择 city 的前六个字符作为前缀索引，如下</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ALTER TABLE city_demo ADD KEY(city(6))</span><br></pre></td></tr></table></figure>

<p>我们当前是以平均选择性为指标的，有时候这样是不够的，还得考虑最坏情况下的选择性，以这个 demo 为例，可能一些人看到选择 4，5 的前缀索引与选择 6，7 的选择性相差不大，那就得看下选择 4，5 的前缀索引分布是否均匀了</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">SELECT </span><br><span class="line">    COUNT(*) AS  cnt, </span><br><span class="line">    LEFT(city, 4) AS pref</span><br><span class="line">  FROM city_demo GROUP BY pref ORDER BY cnt DESC LIMIT 5</span><br></pre></td></tr></table></figure>

<p>可能会出现以下结果</p>
<table>
<thead>
<tr>
<th align="left">cnt</th>
<th align="left">pref</th>
</tr>
</thead>
<tbody><tr>
<td align="left">305</td>
<td align="left">Sant</td>
</tr>
<tr>
<td align="left">200</td>
<td align="left">Toul</td>
</tr>
<tr>
<td align="left">90</td>
<td align="left">Chic</td>
</tr>
<tr>
<td align="left">20</td>
<td align="left">Chan</td>
</tr>
</tbody></table>
<p>可以看到分布极不均匀，以 Sant，Toul 为前缀索引的数量极多，这两者的选择性都不是很理想，所以要选择前缀索引时也要考虑最差的选择性的情况。</p>
<p>前缀索引虽然能实现索引占用空间小且快的效果，但它也有明显的弱点，MySQL 无法使用前缀索引做 ORDER BY 和 GROUP BY ，而且也无法使用前缀索引做覆盖扫描，前缀索引也有可能增加扫描行数。</p>
<p>假设有以下表数据及要执行的 SQL</p>
<table>
<thead>
<tr>
<th align="left">id</th>
<th align="left">email</th>
</tr>
</thead>
<tbody><tr>
<td align="left">1</td>
<td align="left"><a href="mailto:&#x7a;&#104;&#x61;&#x6e;&#x67;&#115;&#115;&#x78;&#x79;&#x7a;&#64;&#49;&#54;&#x33;&#46;&#x63;&#111;&#109;">&#x7a;&#104;&#x61;&#x6e;&#x67;&#115;&#115;&#x78;&#x79;&#x7a;&#64;&#49;&#54;&#x33;&#46;&#x63;&#111;&#109;</a></td>
</tr>
<tr>
<td align="left">2</td>
<td align="left"><a href="mailto:&#x7a;&#104;&#97;&#110;&#103;&#x73;&#49;&#64;&#49;&#54;&#51;&#46;&#x63;&#111;&#x6d;">&#x7a;&#104;&#97;&#110;&#103;&#x73;&#49;&#64;&#49;&#54;&#51;&#46;&#x63;&#111;&#x6d;</a></td>
</tr>
<tr>
<td align="left">3</td>
<td align="left"><a href="mailto:&#122;&#x68;&#97;&#110;&#103;&#115;&#49;&#x40;&#x31;&#54;&#x33;&#46;&#x63;&#111;&#x6d;">&#122;&#x68;&#97;&#110;&#103;&#115;&#49;&#x40;&#x31;&#54;&#x33;&#46;&#x63;&#111;&#x6d;</a></td>
</tr>
<tr>
<td align="left">4</td>
<td align="left"><a href="mailto:&#122;&#104;&#x61;&#110;&#x67;&#x73;&#x31;&#64;&#49;&#54;&#x33;&#x2e;&#99;&#x6f;&#109;">&#122;&#104;&#x61;&#110;&#x67;&#x73;&#x31;&#64;&#49;&#54;&#x33;&#x2e;&#99;&#x6f;&#109;</a></td>
</tr>
</tbody></table>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT id,email FROM user WHERE email&#x3D;&#39;zhangssxyz@xxx.com&#39;;</span><br></pre></td></tr></table></figure>

<p>如果我们针对 email 设置的是整个字段的索引，则上表中根据 「<a href="mailto:&#122;&#104;&#x61;&#x6e;&#103;&#x73;&#x73;&#x78;&#121;&#122;&#x40;&#49;&#54;&#51;&#46;&#x63;&#111;&#x6d;">&#122;&#104;&#x61;&#x6e;&#103;&#x73;&#x73;&#x78;&#121;&#122;&#x40;&#49;&#54;&#51;&#46;&#x63;&#111;&#x6d;</a>」查询到相关记记录后,再查询此记录的下一条记录，发现没有，停止扫描，此时可知<strong>只扫描一行记录</strong>，如果我们以前六个字符（即 email(6)）作为前缀索引，则显然要扫描四行记录，并且获得行记录后不得不回到主键索引再判断 email 字段的值，所以使用前缀索引要评估它带来的这些开销。</p>
<p>另外有一种情况我们可能需要考虑一下，如果前缀基本都是相同的该怎么办，比如现在我们为某市的市民建立一个人口信息表，则这个市人口的身份证虽然不同，但身份证前面的几位数都是相同的，这种情况该怎么建立前缀索引呢。</p>
<p>一种方式就是我们上文说的，针对身份证建立哈希索引，另一种方式比较巧妙，将身份证倒序存储，查的时候可以按如下方式查询:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT field_list FROM t WHERE id_card &#x3D; reverse(&#39;input_id_card_string&#39;);</span><br></pre></td></tr></table></figure>

<p>这样就可以用身份证的后六位作前缀索引了，是不是很巧妙 ^_^</p>
<p>实际上上文所述的索引选择性同样适用于联合索引的设计，如果没有特殊情况，我们一般建议在建立联合索引时，把选择性最高的列放在最前面，比如，对于以下语句：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM payment WHERE staff_id &#x3D; xxx AND customer_id &#x3D; xxx;</span><br></pre></td></tr></table></figure>

<p>单就这个语句而言， (staff_id，customer_id) 和  (customer_id, staff_id) 这两个联合索引我们应该建哪一个呢，可以统计下这两者的选择性。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">SELECT </span><br><span class="line"> COUNT(DISTINCT staff_id)&#x2F;COUNT(*) as staff_id_selectivity,</span><br><span class="line"> COUNT(DISTINCT customer_id)&#x2F;COUNT(*) as customer_id_selectivity,</span><br><span class="line"> COUNT(*)</span><br><span class="line">FROM payment</span><br></pre></td></tr></table></figure>

<p>结果为: ;</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">staff_id_selectivity: 0.0001</span><br><span class="line">customer_id_selectivity: 0.0373</span><br><span class="line">COUNT(*): 16049</span><br></pre></td></tr></table></figure>

<p>从中可以看出 customer_id 的选择性更高，所以应该选择 customer_id 作为第一列。</p>
<h2 id="索引设计准则：三星索引"><a href="#索引设计准则：三星索引" class="headerlink" title="索引设计准则：三星索引"></a>索引设计准则：三星索引</h2><p>上文我们得出了一个索引列顺序的经验 法则：将选择性最高的列放在索引的最前列，这种建立在某些场景可能有用，但通常不如避免随机 IO 和 排序那么重要，这里引入索引设计中非常著名的一个准则：三星索引。</p>
<p>如果一个查询满足三星索引中三颗星的所有索引条件，<strong>理论上</strong>可以认为我们设计的索引是最好的索引。什么是三星索引</p>
<ol>
<li>第一颗星：<strong>WHERE 后面</strong>参与查询的列可以组成了单列索引或联合索引</li>
<li>第二颗星：避免排序，即如果 SQL 语句中出现 order by colulmn，那么取出的结果集就已经是按照 column 排序好的，<strong>不需要再生成临时表</strong></li>
<li>第三颗星：SELECT 对应的列应该尽量是索引列，即<strong>尽量避免回表查询。</strong></li>
</ol>
<p>所以对于如下语句:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT age, name, city where age &#x3D; xxx and name &#x3D; xxx order by age</span><br></pre></td></tr></table></figure>

<p>设计的索引应该是 (age, name,city) 或者 (name, age,city)</p>
<p>当然 了三星索引是一个比较理想化的标准，实际操作往往只能满足期望中的一颗或两颗星，考虑如下语句:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT age, name, city where age &gt;&#x3D; 10 AND age &lt;&#x3D; 20 and city &#x3D; xxx order by name desc</span><br></pre></td></tr></table></figure>

<p>假设我们分别为这三列建了联合索引，则显然它符合第三颗星（使用了覆盖索引），如果索引是（city, age, name)，则虽然满足了第一颗星，但排序无法用到索引，不满足第二颗星，如果索引是 (city, name, age)，则第二颗星满足了，但此时 age 在 WHERE 中的搜索条件又无法满足第一星，</p>
<p>另外第三颗星（尽量使用覆盖索引）也无法完全满足，试想我要 SELECT 多列，要把这多列都设置为联合索引吗，这对索引的维护是个问题，因为每一次表的 CURD 都伴随着索引的更新，很可能频繁伴随着页分裂与页合并。</p>
<p>综上所述，三星索引只是给我们构建索引提供了一个参考，索引设计应该尽量靠近三星索引的标准，但实际场景我们一般无法同时满足三星索引，一般我们会优先选择满足第三颗星（因为回表代价较大）至于第一，二颗星就要依赖于实际的成本及实际的业务场景考虑。</p>
<h2 id="N叉树，跳表skiplist，lsm（Log-Structured-MergeTree）"><a href="#N叉树，跳表skiplist，lsm（Log-Structured-MergeTree）" class="headerlink" title="N叉树，跳表skiplist，lsm（Log-Structured MergeTree）"></a>N叉树，跳表skiplist，lsm（Log-Structured MergeTree）</h2><p>索引<strong>最基本</strong>的东西，N叉树，跳表、LSM我都没讲，同时要创建出好的索引要顾及到很多的方面：</p>
<ul>
<li><strong>最左前缀匹配原则</strong>。这是非常重要、非常重要、非常重要（重要的事情说三遍）的原则，MySQL会一直向右匹配直到遇到范围查询 （&gt;,&lt;,BETWEEN,LIKE）就停止匹配。</li>
<li>尽量选择<strong>区分度高的列作为索引</strong>，区分度的公式是 COUNT(DISTINCT col)/COUNT(*)。表示字段不重复的比率，比率越大我们扫描的记录数就越少。</li>
<li><strong>索引列不能参与计算，尽量保持列“干净”</strong>。比如， FROM_UNIXTIME(create_time)=’2016-06-06’ 就不能使用索引，原因很简单，<strong>B+树中存储的都是数据表中的字段值</strong>，但是进行检索时，需要把所有元素都应用函数才能比较，显然这样的代价太大。所以语句要写成 ：create_time=UNIX_TIMESTAMP(‘2016-06-06’)。</li>
<li>尽可能的<strong>扩展索引</strong>，不要新建立索引。比如表中已经有了a的索引，现在要加（a,b）的索引，那么只需要修改原来的索引即可。</li>
<li>单个多列组合索引和多个单列索引的检索查询效果不同，因为在执行SQL时，<em><strong>MySQL只能使用一个索引</strong>，会从多个单列索引中选择一个限制最为严格的索引</em>(经指正，在MySQL5.0以后的版本中，有“合并索引”的策略，翻看了《高性能MySQL 第三版》，书作者认为：<strong>还是应该建立起比较好的索引，而不应该依赖于“合并索引”这么一个策略</strong>)。</li>
<li>“合并索引”策略简单来讲，就是使用多个单列索引，然后将这些结果用“union或者and”来合并起来</li>
</ul>
<h3 id="b树"><a href="#b树" class="headerlink" title="b树"></a>b树</h3><p>B树是一种平衡多路搜索树。</p>
<p>B树：多路搜索树，每个结点存储M/2到M个关键字，非叶子结点存储指向关键字范围的子结点；所有关键字在整颗树中出现，且只出现一次，非叶子结点可以命中；</p>
<p>B+树：在B-树基础上，为叶子结点增加链表指针，所有关键字都在叶子结点中出现，非叶子结点作为叶子结点的索引；B+树总是到叶子结点才命中；</p>
<p>B*树：在B+树基础上，为非叶子结点也增加链表指针，将结点的最低利用率从1/2提高到2/3；</p>
<h4 id="mongodb-用b树索引"><a href="#mongodb-用b树索引" class="headerlink" title="mongodb 用b树索引"></a>mongodb 用b树索引</h4><p>Mysql中数据遍历操作比较多，所以用B+树作为索引结构。而Mongodb是做单一查询比较多，数据遍历操作比较少，所以用B树作为索引结构。<br>那么为什么Mysql做数据遍历操作多？而Mongodb做数据遍历操作少呢？<br>因为Mysql是关系型数据库，而Mongodb是非关系型数据。</p>
<h4 id="Mongo-db少用关联"><a href="#Mongo-db少用关联" class="headerlink" title="Mongo db少用关联"></a>Mongo db少用关联</h4><p>Mongodb中有一个lookup操作，可以做join查询。但是理想情况下，这个lookup操作应该不会经常使用，如果你需要经常使用它，那么你就使用了错误的数据存储了（数据库）：如果你有相关联的数据，应该使用关系型数据库（SQL）。</p>
<p>因此，正规的设计应该如下<br><img src="https://img2018.cnblogs.com/blog/725429/202002/725429-20200216140737968-740617209.png" alt="img"></p>
<p>假设<code>name</code>这列，我们建了索引！<br>我只寻执行一次语句</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">db.class.find( &#123; name: &#39;1班&#39; &#125; )</span><br></pre></td></tr></table></figure>

<p>这样就能查询出自己想要的结果。</p>
<p>而这，<strong>就是一种单一数据查询!毕竟你不需要去逐行匹配，不涉及遍历操作</strong>,幸运的情况下，有可能一次IO就能够得到你想要的结果。、</p>
<h4 id="区别总结"><a href="#区别总结" class="headerlink" title="区别总结"></a>区别总结</h4><p>因此，由于关系型数据库和非关系型数据的<strong>设计方式上的不同</strong>。</p>
<p>导致在关系型数据中，<strong>遍历操作</strong>比较常见，因此采用B+树作为索引，比较合适。</p>
<p>而在非关系型数据库中，<strong>单一查询</strong>比较常见，因此采用B树作为索引，比较合适。</p>
<h4 id="b-好处"><a href="#b-好处" class="headerlink" title="b+好处"></a>b+好处</h4><p><strong>B+ 树的磁盘 IO 更低</strong> :一次性读入内存中的需要查找的关键字更多</p>
<p><strong>B+ 树的查询效率更加稳定</strong>：必须走一条从根结点到叶子结点的路。类似arrays.sort更倾向稳定</p>
<p><strong>B+ 树元素遍历效率高</strong>：因为双向链表</p>
<h3 id="红黑树"><a href="#红黑树" class="headerlink" title="红黑树"></a>红黑树</h3><p>一种<strong>二叉查找树</strong>,但在每个节点增加一个存储位表示节点的颜色,可以是red或black. 通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树<strong>确保没有一条路径会比其它路径长出两倍</strong>.它是一种弱平衡二叉树(由于是若平衡,可以推出,相同的节点情况下,AVL树的高度低于红黑树),相对于要求严格的AVL树来说,它的旋转次数变少,所以对于搜索,插入,删除操作多的情况下,我们就用红黑树.</p>
<h4 id="性质"><a href="#性质" class="headerlink" title="性质"></a>性质</h4><p><em>1.每个节点非红即黑.</em></p>
<p><em>2.根节点是黑的。</em></p>
<p><em>3.每个叶节点(叶节点即树尾端NUL指针或NULL节点)都是黑的.</em></p>
<p><em>4.如果一个节点是红的,那么它的两儿子都是黑的.</em></p>
<p><em>5.对于任意节点而言,其到叶子点树NIL指针的每条路径都包含相同数目的黑节点</em></p>
<h4 id="适用场景"><a href="#适用场景" class="headerlink" title="适用场景"></a><em>适用场景</em></h4><p><em>1.JAVA中TreeMap就是用的红黑树</em></p>
<p>2.hashmap链表大于8就变红黑树，为何不用跳表（跳表操作快，红黑树查快）</p>
<p>现在想想，我的理解红黑树是让<strong>平衡树（AVL）</strong>更平衡，结构上更加直观，时间效能针对读取而言更高，<strong>但是维护起来比较麻烦！！！</strong>（插入和删除之后，都需要rebalance）。但是，红黑树通过它规则的设定，确保了插入和删除的最坏的时间复杂度是O(log N) 。</p>
<p>设计红黑树的目的，<strong>就是解决平衡树的维护起来比较麻烦的问题，红黑树，读取略逊于AVL，维护强于AVL，每次插入和删除的平均旋转次数应该是远小于平衡树。</strong></p>
<p>小结一下：</p>
<p>能用平衡树的地方，就可以用红黑树。用红黑树之后，读取略逊于AVL，维护强于AVL。</p>
<h4 id="红黑，b-树的用途区别"><a href="#红黑，b-树的用途区别" class="headerlink" title="红黑，b+树的用途区别"></a>红黑，b+树的用途区别</h4><ol>
<li><p><strong>红黑树多用在内部排序，即全放在内存中的，STL的map和set的内部实现就是红黑树。</strong></p>
</li>
<li><p>B+树多用于外存上时，B+也被成为一个磁盘友好的数据结构。</p>
<p>主要有以下两个原因：</p>
<p>（一）磁盘 IO 次数</p>
<p>（二）磁盘预读特性</p>
</li>
</ol>
<h3 id="LSM-树"><a href="#LSM-树" class="headerlink" title="LSM 树"></a>LSM 树</h3><p>目前常见的主要的三种存储引擎是：哈希、B+树、LSM树：</p>
<ul>
<li>哈希存储引擎：是哈希表的持久化实现，支持增、删、改以及随机读取操作，但不支持顺序扫描，对应的存储系统为key-value存储系统。对于key-value的插入以及查询，哈希表的复杂度都是O(1)，明显比树的操作O(n)快,如果不需要有序的遍历数据，哈希表性能最好。</li>
<li>B+树存储引擎是B+树的持久化实现，不仅支持单条记录的增、删、读、改操作，还支持顺序扫描（B+树的叶子节点之间的指针），对应的存储系统就是关系数据库（Mysql等）。</li>
<li>LSM树（Log-Structured MergeTree）存储引擎和B+树存储引擎一样，同样支持增、删、读、改、顺序扫描操作。而且通过批量存储技术规避磁盘随机写入问题。当然凡事有利有弊，LSM树和B+树相比，LSM树牺牲了部分读性能，用来大幅提高写性能。</li>
</ul>
<p>上面三种引擎中，<strong>LSM树存储引擎的代表数据库就是HBase.</strong></p>
<p>LSM树核心思想的核心就是放弃部分读能力，换取写入的最大化能力。LSM Tree ，这个概念就是结构化合并树的意思，<strong>它的核心思路其实非常简单，就是假定内存足够大，因此不需要每次有数据更新就必须将数据写入到磁盘中，而可以先将最新的数据驻留在内存中，等到积累到足够多之后，再使用归并排序的方式将内存内的数据合并追加到磁盘队尾(因为所有待排序的树都是有序的，可以通过合并排序的方式快速合并到一起)。</strong></p>
<p>日志结构的合并树（LSM-tree）是一种基于硬盘的数据结构，与B+tree相比，能显著地减少硬盘磁盘臂的开销，并能在较长的时间提供对文件的高速插入（删除）。<strong>然而LSM-tree在某些情况下，特别是在查询需要快速响应时性能不佳。</strong>通常LSM-tree适用于索引插入比检索更频繁的应用系统。</p>
<p>LSM树和B+树的差异主要在于读性能和写性能进行权衡。在牺牲的同时寻找其余补救方案：</p>
<ol>
<li><p><strong>LSM具有批量特性，存储延迟。当写读比例很大的时候（写比读多），LSM树相比于B树有更好的性能。</strong>因为随着insert操作，为了维护B+树结构，节点分裂。读磁盘的随机读写概率会变大，性能会逐渐减弱。</p>
</li>
<li><p>B树的写入过程：对B树的写入过程是一次原位写入的过程，主要分为两个部分，首先是查找到对应的块的位置，然后将新数据写入到刚才查找到的数据块中，然后再查找到块所对应的磁盘物理位置，将数据写入去。当然，在内存比较充足的时候，因为B树的一部分可以被缓存在内存中，所以查找块的过程有一定概率可以在内存内完成，不过为了表述清晰，我们就假定内存很小，只够存一个B树块大小的数据吧。可以看到，在上面的模式中，需要两次随机寻道（一次查找，一次原位写），才能够完成一次数据的写入，代价还是很高的。</p>
</li>
<li><p>LSM优化方式：</p>
<p>a. Bloom filter: 就是个带随机概率的bitmap,可以快速的告诉你，某一个小的有序结构里有没有指定的那个数据的。于是就可以不用二分查找，而只需简单的计算几次就能知道数据是否在某个小集合里啦。效率得到了提升，但付出的是空间代价。<br> b. compact:小树合并为大树:因为小树性能有问题，所以要有个进程不断地将小树合并到大树上，这样大部分的老数据查询也可以直接使用log2N的方式找到，不需要再进行(N/m)*log2n的查询了</p>
</li>
</ol>
<h3 id="跳表（比红黑树更好操作）"><a href="#跳表（比红黑树更好操作）" class="headerlink" title="跳表（比红黑树更好操作）"></a>跳表（比红黑树更好操作）</h3><h4 id="为何redis-使用跳表做索引，却不是用B-树做索引。"><a href="#为何redis-使用跳表做索引，却不是用B-树做索引。" class="headerlink" title="为何redis 使用跳表做索引，却不是用B+树做索引。"></a>为何redis 使用跳表做索引，却不是用B+树做索引。</h4><ol>
<li><p>内存小，所以索引不能多，跳表稀疏点好。操作也快。</p>
</li>
<li><p>即使稀疏，但是内存本来快所以影响不大，属于牺牲查找来换取操作性能和空间。</p>
</li>
<li><p>页与硬盘的页都是4kb，加预读机制</p>
</li>
</ol>
<p>因为B+树的原理是 叶子节点存储数据，非叶子节点存储索引，B+树的每个节点可以存储多个关键字，它将节点大小设置为磁盘页的大小，充分利用了磁盘预读的功能。每次读取磁盘页时就会读取一整个节点,每个叶子节点还有指向前后节点的指针，为的是最大限度的降低磁盘的IO;因为数据在内存中读取耗费的时间是从磁盘的IO读取的百万分之一。</p>
<ol start="2">
<li>跳表，可以有序加稀疏省空间</li>
</ol>
<p>传统意义的单链表是一个线性结构，向有序的链表中插入一个节点需要O(n)的时间，查找操作需要O(n)的时间。</p>
<p><img src="https://pic1.zhimg.com/80/v2-4e1a4b77950dd47c7dfdb043c5661cbc_720w.png" alt="img"></p>
<p>使用上面一层的跳表，可以减少所需查询时间为O(n/2)，可以根据实际情况对链表进行创建多层索引。</p>
<h4 id="为何不用红黑树用跳表"><a href="#为何不用红黑树用跳表" class="headerlink" title="为何不用红黑树用跳表"></a>为何不用红黑树用跳表</h4><p>跳表是使用空间换取时间的一个算法，使用概率均衡技术而不是强制均衡技术，<strong>对于插入和删除比传统上的平衡树算法更加高效。</strong></p>
<h4 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h4><p>在java中可以使用ConcurrentHashMap来实现多线程的map存取，如果实现多线程有序map存取可以使用ConcurrentSkipList来实现。</p>

            </div>
        
        <footer class="article-footer">
        </footer>
    </div>
</article>


    
<nav id="article-nav">
    
        <a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/4-mysql-explain%E6%89%A7%E8%A1%8C%E5%85%B7%E4%BD%93%E6%B5%81%E7%A8%8B/" id="article-nav-newer" class="article-nav-link-wrap">
            <strong class="article-nav-caption">Newer</strong>
            <div class="article-nav-title">
                
                    4-mysql-explain执行具体流程
                
            </div>
        </a>
    
    
        <a href="/gitee-internal-blog/2021/09/04/%E6%95%B0%E6%8D%AE%E5%BA%93/mysql/8-mysql-%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0%E8%AE%BE%E5%A4%9A%E5%A4%A7/" id="article-nav-older" class="article-nav-link-wrap">
            <strong class="article-nav-caption">Older</strong>
            <div class="article-nav-title">8-mysql-数据库连接池设多大</div>
        </a>
    
</nav>





    
    




<!-- baidu url auto push script -->
<script type="text/javascript">
    !function(){var e=/([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,r=window.location.href,o=document.referrer;if(!e.test(r)){var n="//api.share.baidu.com/s.gif";o?(n+="?r="+encodeURIComponent(document.referrer),r&&(n+="&l="+r)):r&&(n+="?l="+r);var t=new Image;t.src=n}}(window);
</script>     
</section>
        </div>
        <footer id="footer">
    <div class="outer">
        <div id="footer-info" class="inner">
            Johnny &copy; 2023 
            <a rel="license noopener" target="_blank" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-nd/4.0/80x15.png" /></a>
            <br> Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>. Theme - <a target="_blank" rel="noopener" href="https://github.com/zthxxx/hexo-theme-Wikitten">wikitten</a>
            
                <br>
                <span id="busuanzi_container_site_pv"><i class="fa fa-eye"></i> <span id="busuanzi_value_site_pv"></span></span>
                &nbsp;|&nbsp;
                <span id="busuanzi_container_site_pv"><i class="fa fa-user"></i> <span id="busuanzi_value_site_uv"></span></span>
            
        </div>
    </div>
</footer>

        

    
        
<script src="/gitee-internal-blog/libs/lightgallery/js/lightgallery.min.js"></script>

        
<script src="/gitee-internal-blog/libs/lightgallery/js/lg-thumbnail.min.js"></script>

        
<script src="/gitee-internal-blog/libs/lightgallery/js/lg-pager.min.js"></script>

        
<script src="/gitee-internal-blog/libs/lightgallery/js/lg-autoplay.min.js"></script>

        
<script src="/gitee-internal-blog/libs/lightgallery/js/lg-fullscreen.min.js"></script>

        
<script src="/gitee-internal-blog/libs/lightgallery/js/lg-zoom.min.js"></script>

        
<script src="/gitee-internal-blog/libs/lightgallery/js/lg-hash.min.js"></script>

        
<script src="/gitee-internal-blog/libs/lightgallery/js/lg-share.min.js"></script>

        
<script src="/gitee-internal-blog/libs/lightgallery/js/lg-video.min.js"></script>

    
    
        
<script src="/gitee-internal-blog/libs/justified-gallery/jquery.justifiedGallery.min.js"></script>

    
    
        <script type="text/x-mathjax-config">
    MathJax.Hub.Config({
        tex2jax: {
            inlineMath: [ ["$","$"], ["\\(","\\)"] ],
            skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'],
            processEscapes: true,
            TeX: {
                equationNumbers: {
                  autoNumber: 'AMS'
                }
            }
        }
    });
    MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax();
        for (var i = 0; i < all.length; ++i)
            all[i].SourceElement().parentNode.className += ' has-jax';
    });
</script>
<script async src="//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    



<!-- Custom Scripts -->

<script src="/gitee-internal-blog/js/main.js"></script>


    </div>
</body>
</html>